﻿using System.Linq;
using System.Security.Claims;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;

namespace BlazorWasm
{
    public class CustomUserFactory 
        : AccountClaimsPrincipalFactory<RemoteUserAccount>
    {
        public CustomUserFactory(IAccessTokenProviderAccessor accessor)
        : base(accessor)
        {
        }

        public async override ValueTask<ClaimsPrincipal> CreateUserAsync(
            RemoteUserAccount account,
            RemoteAuthenticationUserOptions options)
        {
            var user = await base.CreateUserAsync(account, options);

            if (user.Identity.IsAuthenticated)
            {
                var identity = (ClaimsIdentity)user.Identity;
                ParseArrayClaims(account, identity, identity.RoleClaimType, options.RoleClaim);
                ParseArrayClaims(account, identity, "permission", "permission");
            }

            return user;
        }

        private void ParseArrayClaims(RemoteUserAccount account, 
            ClaimsIdentity identity, 
            string srcClaimType, string destClaimType)
        {
            var srcClaims = identity.FindAll(srcClaimType);

            if (srcClaims != null && srcClaims.Any())
            {
                foreach (var existingClaim in srcClaims)
                {
                    identity.RemoveClaim(existingClaim);
                }

                var srcEle = account.AdditionalProperties[srcClaimType];

                if (srcEle is JsonElement srcClaimValues)
                {
                    if (srcClaimValues.ValueKind == JsonValueKind.Array)
                    {
                        foreach (var srcValue in srcClaimValues.EnumerateArray())
                        {
                            identity.AddClaim(new Claim(destClaimType, srcValue.GetString()));
                        }
                    }
                    else
                    {
                        identity.AddClaim(new Claim(destClaimType, srcClaimValues.GetString()));
                    }
                }
            }
        }
    }
}
